/*
 * Copyright (c) 2006-2025, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-10-14     RT-Thread    aht20 driver
 */

#include <rtthread.h>
#include <rtdevice.h>
#include "drv_aht20.h"

#define DBG_TAG "drv.aht20"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

static rt_err_t aht20_write_cmd(aht20_device_t dev, rt_uint8_t cmd, rt_uint8_t *data, rt_size_t len)
{
    struct rt_i2c_msg msgs;
    rt_uint8_t buf[3];

    buf[0] = cmd;
    if (data != RT_NULL && len > 0)
    {
        rt_memcpy(&buf[1], data, len);
    }

    msgs.addr = AHT20_I2C_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = 1 + len;

    if (rt_i2c_transfer(dev->i2c, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

static rt_err_t aht20_read_data(aht20_device_t dev, rt_uint8_t *buf, rt_size_t len)
{
    struct rt_i2c_msg msgs;

    msgs.addr = AHT20_I2C_ADDR;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;

    if (rt_i2c_transfer(dev->i2c, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

aht20_device_t aht20_init(const char *i2c_bus_name)
{
    aht20_device_t dev = RT_NULL;
    rt_uint8_t temp[2];

    dev = rt_calloc(1, sizeof(struct aht20_device));
    if (dev == RT_NULL)
    {
        LOG_E("Can't allocate memory for aht20 device");
        return RT_NULL;
    }

    dev->i2c = (struct rt_i2c_bus_device *)rt_device_find(i2c_bus_name);
    if (dev->i2c == RT_NULL)
    {
        LOG_E("Can't find %s device", i2c_bus_name);
        rt_free(dev);
        return RT_NULL;
    }

    dev->lock = rt_mutex_create("aht20", RT_IPC_FLAG_FIFO);
    if (dev->lock == RT_NULL)
    {
        LOG_E("Can't create mutex for aht20 device");
        rt_free(dev);
        return RT_NULL;
    }

    rt_thread_mdelay(40);

    temp[0] = 0x08;
    temp[1] = 0x00;
    if (aht20_write_cmd(dev, AHT20_CMD_CALIBRATE, temp, 2) != RT_EOK)
    {
        LOG_E("AHT20 calibrate failed");
        rt_mutex_delete(dev->lock);
        rt_free(dev);
        return RT_NULL;
    }

    rt_thread_mdelay(10);

    LOG_I("AHT20 init success");

    return dev;
}

void aht20_deinit(aht20_device_t dev)
{
    if (dev != RT_NULL)
    {
        rt_mutex_delete(dev->lock);
        rt_free(dev);
    }
}

rt_err_t aht20_read_temperature_humidity(aht20_device_t dev, float *temperature, float *humidity)
{
    rt_uint8_t buf[6];
    rt_uint8_t cmd_data[2];
    rt_uint32_t humi_raw, temp_raw;
    rt_err_t result = RT_EOK;

    if (dev == RT_NULL)
    {
        return -RT_ERROR;
    }

    rt_mutex_take(dev->lock, RT_WAITING_FOREVER);

    cmd_data[0] = 0x33;
    cmd_data[1] = 0x00;
    result = aht20_write_cmd(dev, AHT20_CMD_TRIGGER, cmd_data, 2);
    if (result != RT_EOK)
    {
        LOG_E("AHT20 trigger measurement failed");
        rt_mutex_release(dev->lock);
        return result;
    }

    rt_thread_mdelay(80);

    result = aht20_read_data(dev, buf, 6);
    if (result != RT_EOK)
    {
        LOG_E("AHT20 read data failed");
        rt_mutex_release(dev->lock);
        return result;
    }

    if ((buf[0] & 0x80) != 0x00)
    {
        LOG_E("AHT20 data not ready");
        rt_mutex_release(dev->lock);
        return -RT_ERROR;
    }

    humi_raw = ((rt_uint32_t)buf[1] << 12) | ((rt_uint32_t)buf[2] << 4) | ((buf[3] & 0xF0) >> 4);
    temp_raw = (((rt_uint32_t)buf[3] & 0x0F) << 16) | ((rt_uint32_t)buf[4] << 8) | buf[5];

    *humidity = (humi_raw * 100.0) / 1048576.0;
    *temperature = (temp_raw * 200.0 / 1048576.0) - 50.0;

    rt_mutex_release(dev->lock);

    return RT_EOK;
}
